%start markdowns
%token 'u' 'v' 'w'  
%expect-unused 'u' 'v'  'w'
%nonassoc  'Line'
%nonassoc 'u' 
%left 'TableHead' 'TableHeadLeftAlign' 'TableHeadRightAlign' 'TableHeadCenterAlign'
%right   '('  '[' 
%left  '!'  '|'   'HeadStart' 'ListItem' 'UN_ORDER_ASTERISK_LISTITEM' 'UN_ORDER_PLUS_LISTITEM' 'UN_ORDER_MINUS_LISTITEM' 'CHECK_LISTTIEM' 'UNCHECK_LISTTIEM'
%left 'C' 'EC' 'BR'
%left 'Bold' 'Italic' 'Underscore' "DeleteLine"
%left 'Blank' 
%left    ']' ')' 
%nonassoc 'v'
%nonassoc 'w'
%parse-param listener:&TListener
%%
markdowns -> Vec<Markdown<'input>>:
        markdown {
             listener.borrow_mut().when(&$1);
            vec![$1]
        }
        | markdowns markdown {
             listener.borrow_mut().when(&$2);
            $1.push($2);
            $1
        }
        ;
markdown -> Markdown<'input>:
        heading {$1}
        |paragraph %prec 'u'{ generate_text($1)}
        |code {$1}
        |list %prec 'u'{generate_markdown_list($1,true)}
        |unOrderList %prec 'u'{generate_markdown_list($1,false)}
        |checkableList %prec 'u'{generate_markdown_checkable_list($1)}
        |table  {$1}
        |'Line' %prec 'u'{Markdown::Nul}
    ;

code -> Markdown<'input>:
    'CodeStart' codeContent 'CodeEnd' {
        generate_code($lexer,$2)
        }
    ;
codeContent -> Result<Span,()>:
        'Code' {Ok($span)}
        | codeContent 'Code' { Ok($span)}
;
heading -> Markdown<'input>:
    'HeadStart'   line  { generate_head($lexer,$2,$1.unwrap().span()) }
    ;
paragraph -> TextList<'input>:
     lineInP %prec 'u'{$1}   
     | paragraph lineInP %prec 'u' {
        let mut ans = $1;
        (&mut ans).append($2,$lexer);
         ans
     }
     | paragraph lof %prec 'u'{
        let mut ans = $1;
        (&mut ans).append_line_break();
         ans
     }
    ;
listItemPragraph -> TextList<'input>:
     line %prec 'u'{$1}
     | listItemPragraph lineInP  {
        let mut ans = $1;
        (&mut ans).append($2,$lexer);
         ans
     }
     | listItemPragraph lof {
        let mut ans = $1;
        (&mut ans).append_line_break();
         ans
     }
    ;
line -> TextList<'input>:
   texts lof {$1 }
;
texts -> TextList<'input>:
    text {$1.0}
    |text ')' {
        let mut ans = $1.0;
        let a = generate_plaint($lexer,$2.unwrap().span()).0;
        ans.append(a,$lexer);
        ans
    }
    |text ')' text{
        let mut ans = $1.0;
        let a = generate_plaint($lexer,$2.unwrap().span()).0;
        ans.append(a,$lexer);
        ans.append($3.0,$lexer);
        ans
    }
;
lineInP -> TextList<'input>:
       lineStartInP lof {$1.0 }
       |lineStartInP textInP lof {
        let mut ans = $1.0;
        ans.append($2.0,$lexer);
        ans
       }
;
lineStartInP ->(TextList<'input>,Span): 
    cStartInP {($1,$span)}
    |'Blank' cStartInP %prec 'u'{($2,$span)}
    |'Blank' 'HeadStart' %prec 'u'{generate_plaint($lexer,$span)}
    |'Blank'  %prec 'u'{generate_plaint($lexer,$span)}
;
cStartInP ->TextList<'input>: 
    'C' { generate_plaint($lexer,$span).0}
    |'(' {generate_plaint($lexer,$span).0}
    |')' {generate_plaint($lexer,$span).0}
    |']' {generate_plaint($lexer,$span).0}
    | 'Bold' %prec 'u'{  generate_plaint($lexer,$span).0 }
    | 'BR' %prec 'u'{  generate_br() }
    | 'Italic' %prec 'u'{  generate_plaint($lexer,$span).0 }
    | 'Underscore' %prec 'u'{  generate_plaint($lexer,$span).0 }
    | 'DeleteLine' %prec 'u'{  generate_plaint($lexer,$span).0 }
    |'EC' {
        let span = if $span.start()+1 < $span.end(){
            Span::new($span.start()+1,$span.end())
        } else{
            $span
        } ;
        generate_plaint($lexer,span).0
        }
    |tableAlign %prec 'u'{generate_plaint($lexer,$span).0} 
    |image {TextList{items:vec![$1]} }
    |noImage  %prec 'u'{$1}
    |link {TextList{items:vec![$1]} }
    |noLink {$1}
    |bold %prec 'u'{$1}
    |italic %prec 'u'{$1}
    |underscore %prec 'u'{ $1 }
    |deleteLine %prec 'u'{ $1 }
;
textInP -> (TextList<'input>,Span):
    chunkInP %prec 'u'{$1}
    | '|'  %prec 'u'{generate_plaint($lexer,$span)}
     |textInP chunkInP{
        let mut ans = $1.0;
        (&mut ans).append($2.0,$lexer);
         (ans,$span)
    }
;
chunkInP -> (TextList<'input>,Span):
    chunk %prec 'u'{($1,$span)}
    | 'Bold' %prec 'u'{  generate_plaint($lexer,$span) }
    | 'Italic' %prec 'u'{  generate_plaint($lexer,$span) }
    | 'Underscore' %prec 'u'{  generate_plaint($lexer,$span) }
    | 'DeleteLine' %prec 'u'{  generate_plaint($lexer,$span) }
    | ']' %prec 'u' {generate_plaint($lexer,$span)}
    | ')' %prec 'u' {generate_plaint($lexer,$span)}
    ;
    
text -> (TextList<'input>,Span):
    chunk %prec 'u'{($1,$span)}
    | '|' %prec 'u'{generate_plaint($lexer,$span)}
    |']' %prec 'u' {generate_plaint($lexer,$span)}
    |')' %prec 'u' {generate_plaint($lexer,$span)}
    | text chunk{
        let mut ans = $1.0;
        (&mut ans).append($2,$lexer);
         (ans,$span)
    }
;
chunk -> TextList<'input>:
    'C' { generate_plaint($lexer,$span).0}
    | 'BR' %prec 'u'{generate_br()}
    |'(' {generate_plaint($lexer,$span).0}
    |'(' ')' {generate_plaint($lexer,$span).0}
    |'EC' {
        let span = if $span.start()+1 < $span.end(){
            Span::new($span.start()+1,$span.end())
        } else{
            $span
        } ;
        generate_plaint($lexer,span).0
        }
    | 'ListItem' {generate_plaint($lexer,$span).0}
    | unOrderListItemHead {generate_plaint($lexer,$span).0}
    | checkableItemHead {generate_plaint($lexer,$span).0}
    |'HeadStart' %prec 'u'{generate_plaint($lexer,$span).0}
    |tableAlign %prec 'u'{generate_plaint($lexer,$span).0} 
    |image {TextList{items:vec![$1]} }
    |noImage  %prec 'u'{$1}
    |link {TextList{items:vec![$1]} }
    |noLink {$1}
    |bold %prec 'u'{$1}
    |italic %prec 'u'{$1}
    |'Blank' %prec 'u'{generate_plaint($lexer,$span).0}
    |underscore %prec 'u'{ $1 }
    |deleteLine %prec 'u'{ $1 }
;
squareText -> (TextList<'input>,Span):
     '[' text ']'  %prec 'u'{
        let mut ans = generate_plaint($lexer,$1.unwrap().span()).0;
        let  a = generate_plaint($lexer,$3.unwrap().span()).0;
        $2.0.append(a,$lexer);
        ans.append($2.0,$lexer);
        ( ans ,$span)
    }
;
noLink ->TextList<'input>:
   squareText '(' text  %prec 'u'{
        let mut ans = $1.0;
        let mut a = generate_plaint($lexer,$2.unwrap().span()).0;
        let b = $3.0;
        a.append(b,$lexer);
        ans.append(a,$lexer);
        ans
   }
    | squareText '('   %prec 'u'{
        let mut ans = $1.0;
        let a = generate_plaint($lexer,$2.unwrap().span()).0;
        ans.append(a,$lexer);
        ans
    }
    | squareText   %prec 'u'{
        $1.0
    }
    | '[' text     %prec 'u'{ 
        let mut ans = generate_plaint($lexer,$1.unwrap().span()).0;
        ans.append($2.0,$lexer);
        ans
     }
    | '['      %prec 'u'{ generate_plaint($lexer,$span).0 }
    ;
link ->Block<'input>:
   squareText '(' text ')'  { generate_link($lexer,$1.1,$3.1) }
    ;
noImage ->TextList<'input>:
    '!'       %prec 'u'{ generate_plaint($lexer,$span).0 }
    | noImage noLink  %prec 'u'{ 
        let mut ans = $1;
        (&mut ans).append($2,$lexer);
        ans
     }
    ;
image -> Block<'input>:
   '!' link  { generate_image($2) }
    ;
list -> Vec<ListItem<'input>>:
    listItem {generate_list($1)}
    | list listItem {
        let mut ans = $1;
        append_item(&mut ans,$2);
        ans
    }
    ;
listItem ->ListItem<'input>:
    'ListItem' listItemPragraph %prec 'u'{
        let span1 = $1.unwrap().span();
        let level = span1.len()-$lexer.span_str(span1).trim_start().len();    
         generate_list_item($lexer,level,$2) 
    }
    ;
unOrderList -> Vec<ListItem<'input>>:
    unOrderListItem {generate_list($1)}
    | unOrderList unOrderListItem {
        let mut ans = $1;
        append_item(&mut ans,$2);
        ans
    }
    ;
unOrderListItem ->ListItem<'input>:
    unOrderListItemHead listItemPragraph %prec 'u'{
        let span1 = $1.1;
        let level = span1.len()-$lexer.span_str(span1).trim_start().len();    
         generate_list_item($lexer,level,$2) 
    }
    ;
unOrderListItemHead -> ( TextList<'input>,Span ):
    "UN_ORDER_ASTERISK_LISTITEM" {generate_plaint($lexer,$span)}
    |"UN_ORDER_PLUS_LISTITEM" {generate_plaint($lexer,$span)}
    |"UN_ORDER_MINUS_LISTITEM" {generate_plaint($lexer,$span)}
    ;
checkableList -> Vec<CheckableListItem<'input>>:
    checkableListItem {generate_checkable_list($1)}
    | checkableList checkableListItem {
        let mut ans = $1;
        append_checkable_list_item(&mut ans,$2);
        ans
    }
    ;
checkableListItem ->CheckableListItem<'input>:
    checkableItemHead listItemPragraph %prec 'v'{
        let span1 = $1.1;
        let level = span1.len()-$lexer.span_str(span1).trim_start().len();    
         generate_checkable_list_item($lexer,level,$2,$1.0) 
    }
    ;
checkableItemHead -> ( bool,Span ):
    "CHECK_LISTTIEM" {(true,$span)}
    |"UNCHECK_LISTTIEM" {(false,$span)}
    ;
table -> Markdown<'input>:
     row  tableAlignRow rows %prec 'u'{
        Markdown::Table{
            heads:$1,
            aligns:$2,
            rows:$3
        }
     }
    ;

tableAlignRow -> Vec<TableAlign>:
    tableAlignCells '|' lof {$1}
;
tableAlignCells -> Vec<TableAlign>:
     '|' tableAlign   {vec![$2]}
    |tableAlignCells '|' tableAlign   {
        let mut ans = $1;
        ans.push($3);
        ans 
    }
    ;
tableAlign -> TableAlign:
     'TableHead'  {TableAlign::Left}
    | 'TableHeadLeftAlign' {TableAlign::Left}
    | 'TableHeadRightAlign' {TableAlign::Right}
    | 'TableHeadCenterAlign' {TableAlign::Center}
    ;
rows -> Vec<Row<'input>>:
     row {vec![$1]}
    |rows row {
        let mut ans = $1;
        ans.push($2);
        ans 
    }
    ;

row -> Row<'input>:
 cells '|' lof  {$1} 
;
cells -> Row<'input>:
    cell {Row{cells:vec![$1]}}
    | cells  cell {
        let mut ans = $1;
        ans.cells.push($2);
        ans 
    }
    ;
cell -> TextList<'input>:
    '|' text  { $2.0}
    | '|'  {TextList::new_by_empty_str()}
;
lof -> Result<(),()>:
     'Line' {Ok(())}
    | 'EOF' {Ok(())}
    ;
bold -> TextList<'input>:
     'Bold' text 'Bold'  %prec 'v' { generate_decorater($lexer,$2.0,Decorater::Bold) }
    |'Bold' text  %prec 'u' { generate_plaint($lexer,$span).0 }
    ;
italic -> TextList<'input>:
    'Italic' text 'Italic'   %prec 'v' { generate_decorater($lexer,$2.0,Decorater::Italic) }
    | 'Italic' text %prec 'u'{ generate_plaint($lexer,$span).0 }
    ;
underscore -> TextList<'input>:
    'Underscore' text 'Underscore'   %prec 'v'{ generate_decorater($lexer,$2.0,Decorater::Underscore) }
    |'Underscore' text %prec 'u'{ generate_plaint($lexer,$span).0 }
    ;
deleteLine -> TextList<'input>:
    'DeleteLine' text 'DeleteLine'   %prec 'v'{ generate_decorater($lexer,$2.0,Decorater::DeleteLine) }
    |'DeleteLine' text %prec 'u'{ generate_plaint($lexer,$span).0 }
    ;
%%
// Any functions here are in scope for all the grammar actions above.
use markdown_elements::*;
use lrpar::Span;
//type StorageT = u32;
//fn map_err<StorageT>(r: Result<impl Lexeme<StorageT>,impl Lexeme<StorageT>>)
//        -> Result<impl Lexeme< StorageT>, ()>
//{
//    r.map_err(|_| ())
//}